//! Wade-Giles Romanization
//! 
//! `PINYIN_DATA` 拼音字典去重后的威妥玛拼音集
//! 
//! `*_CHAR_INDEX` 汉字字符威妥玛拼音位置图表
//! 
//! `SMALL_CHAR_INDEX` Unicode 码表索引 U+2E80..U+2EFF、U+3000..U+303F、U+31C0..U+31EF、U+3200..U+32FF、
//!     U+3300..U+33FF、U+3400..U+4DBF、U+4E00..U+9FFF、U+F900..U+FAFF、U+FE30..U+FE4F、U+20000..U+223AF
//! 
//! `BIG_CHAR_INDEX` Unicode 码表索引 U+223B0..U+323AF
//! 
//! `SMALL_CHAR_INDEX` + `BIG_CHAR_INDEX` 覆盖目前 Unicode 码表中所以汉字索引
//! 
//! `*_CODE` 切分 `*_CHAR_INDEX` 边界值
//! 
//! 流程: 汉字字符 -> `unicode_transform()` -> 位置图 key -> `*_CHAR_INDEX` -> 位置索引 -> `PINYIN_DATA` -> 威妥玛拼音
//! 
//! `*_CHAR_INDEX` 目前采用 `binary_search_by_key()` 实现 (对于稀疏数组来说足够快了)，若速度有需求可换为 `hashmap`
//! 
//! `*_CHAR_INDEX` 切分方式使得其 (key, value) 都使用 u16 类型存储，降低了至少 1/3 内存与硬盘的存储开销 (可切分为 u8 数据容量大小的块，但对 `unicode_transform()` 并不经济)
//! 
//! `*_CHAR_INDEX`、`PINYIN_DATA`... 均由 build.rs 通过获取在线数据更新生成，无需手动维护

use solutiont4::data::*;

pub fn converter(input: &str) -> String {
    input.chars()
        .enumerate()
        .filter_map(|(i, c)| {
            let unicode = u32::from_str_radix(
                &c.escape_unicode().to_string()
                    .replace("\\u{", "")
                    .replace("}", ""), 
                16).unwrap();
            let index = unicode_transform(unicode)?;
            let mut wade_giles = PINYIN_DATA[index].to_string();
            if i == 0 && !wade_giles.is_empty() {
                wade_giles = format!("{}{}", &wade_giles[..1].to_uppercase(), &wade_giles[1..]);
            }
            Some(wade_giles)
        }).collect::<Vec<_>>().join(" ")
}

#[inline(always)]
fn unicode_transform(unicode: u32) -> Option<usize> {
    let mut index;
    if unicode > 0x323AF || unicode < SMALL_CODE {
        return None
    } else if unicode >= BIG_CODE {
        index = BIG_CHAR_INDEX.binary_search_by_key(&((unicode - BIG_CODE) as u16), |&(key, _)| key).ok()?;
        index = BIG_CHAR_INDEX[index].1 as usize;
    } else if unicode >= MEDIUM_CODE {
        index = SMALL_CHAR_INDEX.binary_search_by_key(&((unicode - MEDIUM_CODE) as u16), |&(key, _)| key).ok()?;
        index = SMALL_CHAR_INDEX[index].1 as usize;
    } else if unicode > 0xFE4F  {
        return None
    } else {
        index = SMALL_CHAR_INDEX.binary_search_by_key(&((unicode - SMALL_CODE) as u16), |&(key, _)| key).ok()?;
        index = SMALL_CHAR_INDEX[index].1 as usize;
    }
    Some(index)
}